"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

from threading import Thread
from msnp.persistence import PersistenceController, XMLController
from msnp.service.synch import SynchChange, NetSynchController
from msnp.gui import MySignal
from msnp.logger import Logger
from msnp.service.synch.player.amarok import AmarokSynchChanges
from msnp.model import MediaModel, PTPModel
from msnp.service.synch.timer import SynchChangesTimer, RescanTimer
from msnp.service.utils import ProcessUtils
from msnp.model.MediaModel import NetSynchChanges

"""This module contains all functions needed for synchronization with the media player:
- import data from the player database
- retrieve all data from the media database
- synchronize with the player (write changes coming from the network into the player database)"""

class ImportPlayerDataThread(Thread):
    """Class for importing all data from the player's database into the media database.
    
    Attributes:
        __settings: The settings of the settings XML file, needed to retrieve the database settings.
    """
    
    def __init__(self, settings):
        """The init method."""
        Thread.__init__(self)
        self.__settings = settings

    def run(self):
        """Executes the SynchChangesTimer so that all changes from the player get written into the SynchChanges table.
        Then it reads all entries of the player database and writes them into the media database.
        A progress bar is opened to see the progress.
        All changes are logged and the process to synchronize with other users is started.
        """
        playerDBSettings = self.__settings.getCurrentUserSettings().getPlayerDatabaseSettings()
        mediaDBSettings = self.__settings.getCurrentUserSettings().getMediaDatabaseSettings()
        PersistenceController.initPlayerDatabase(playerDBSettings, mediaDBSettings.getSchema())
        #execute SynchChangeTimer and stop it
        SynchChangesTimer.runAndStopTimer()
        audios = PersistenceController.selectPlayerAudiosFromPlayerDB()
        synchWriter = SynchChange.SynchChangesWriter()
        if audios != None and len(audios) > 0:
            MySignal.emitOpenProgressBarSignal(len(audios), True)
            progressCount = 1
            for audio in audios:
                MySignal.emitUpdateProgressBarSignal(progressCount)
                synchWriter.processChange(audio)
                progressCount += 1
        
        # log changes in the net synch changes table
        changedMediaIds = synchWriter.getChangedMediaIds()
        if changedMediaIds != None and len(changedMediaIds) > 0:
            netSynchChange = NetSynchChanges(None, None, None, None, None, True, MediaModel.NetSynchChangeSource.PLAYER)
            for changedMediaId in changedMediaIds:
                netSynchChange.setMediaId(changedMediaId)
                PersistenceController.insertNetSynchChange(netSynchChange)

            NetSynchController.pushMediaContent()
        
        #delete synch changes
        PersistenceController.deleteSynchChanges()
        #start synch changetimer again
        SynchChangesTimer.startSynchChangesTimer()
        MySignal.emitSynchEnableSignal(True, False, PTPModel.ReturnType.SUCCESSFUL)
        
class ReadAllStoredAudiosThread(Thread):
    """Class for reading all audios stored in the media database."""
    
    def __init__(self):
        """The init method."""
        Thread.__init__(self)
        
    def run(self):
        """Reads all entries of the media database."""
        audios = PersistenceController.selectAllAudios()
        Logger.info("got " + str(len(audios)) + " audios from the database")
        MySignal.emitAudiosRetrievedSignal(audios)

class SynchronizeWithPlayerThread(Thread):
    """Class for synchronizing from the media database to the player database."""
     
    def __init__(self):
        """The init method."""
        Thread.__init__(self)
        
    def run(self):
        """Synchronizes from the media database to the player's database.
        
        The media database changes only if the change came from the player
        (so the player is already up-to-date) or when an update camo from another peer.
        In that case the changes got logged in the media database (NetSynchChanges).
        Therefore it reads this changes and updates the player database accordingly.
        If the player is Amarok it afterwards kills and restarts the player
        so that changes in the player database get adopted in the player.
        """
   
        settings = XMLController.readAllSettings()
        if settings.getCurrentUserSettings().getPlayerDatabaseSettings().getPlayer() == MediaModel.Player.AMAROK().getName():
            #execute SynchChangeTimer and stop it
            SynchChangesTimer.runAndStopTimer()
            #synch from Media to Amarok database
            synchReader = AmarokSynchChanges.AmarokSynchChangesReader()
            #if there were changes
            if synchReader.processChanges():
                #tell the user that the player will be restarted
                MySignal.emitRestartPlayerSignal()
                #If amarok is running -> stop it
                pid = ProcessUtils.getPIDForPlayer(MediaModel.Player.AMAROK())
                ProcessUtils.killProcessById(pid)
                #wait until amarok scanned the collection
                RescanTimer.startTimer()
                #start amarok again
                ProcessUtils.startPlayerProcess(MediaModel.Player.AMAROK())
            else:
                #start timer again
                SynchChangesTimer.startSynchChangesTimer()
                #show dialog and enable synchronization
                MySignal.emitNothingToSynchSignal()
                MySignal.emitSynchEnableSignal(True, True, PTPModel.ReturnType.SUCCESSFUL)
                
        else:
            MySignal.emitSynchEnableSignal(True, True, PTPModel.ReturnType.NO_PLAYER_SELECTED)
    

def importPlayerData():
    """Initializes and starts a thread to import all audios from the player database into the media database."""
    settings = XMLController.readAllSettings()
    importThread = ImportPlayerDataThread(settings)
    importThread.start()
    
def readAllStoredAudios():
    """Initializes and starts a thread to read all audios from the media database."""
    readAudiosThread = ReadAllStoredAudiosThread()
    readAudiosThread.start()
    
def synchWithPlayer():
    """Initializes and starts a thread to synchronize the media database with the player's database."""
    synchThread = SynchronizeWithPlayerThread()
    synchThread.start()
    
